
#include "packet.h"
#include "messagepacket.h"

int intOfBa(int nbytes, QByteArray *bytes)
{
    int i, j;
    int result = 0;
    int power = 1;
    for (i = nbytes - 1; i >= 0; i--)
    {
        for (j = 0; j < 8; j++)
        {
            if ((bytes->at(i) >> j) & 1) result += power;
            power *= 2;
        }
    }
    return result;
}

//Decodes, extracts and removes a Packet from the QByteArray buffer. Returns null and does nothing if there isn't a full packet.
Packet *Packet::readPacket(QByteArray *buffer)
{
    QByteArray id;
    QByteArray size;
    Packet *result = NULL;
    int iId = 0, iSize = 0;
    if (buffer != NULL) {
        if (buffer->size() < 4) {
            return NULL;
        } else {
            id = buffer->left(1);
            size = buffer->mid(1,3);
            iId = intOfBa(1, &id);
            iSize = intOfBa(3, &size);
            if (buffer->size() - 4 < iSize) {
                return NULL;
            } else {
                QByteArray temporal(buffer->mid(4, iSize));
                switch(iId)
                {
                case 1: // MessagePacketID
                    result = new MessagePacket::MessagePacket();
                    result->setFromBuffer(&temporal);
                    break;
                default:
                    // Wrong packet received (discard)
                    break;
                }
                buffer->remove(0, 4 + iSize);
            }
            return result;
        }
    }
    return NULL;
}

QByteArray baOfInt(int nbytes, int integer)
{
    int i, j;
    QByteArray *result = new QByteArray(nbytes,'\0');
    for (i = nbytes - 1; i >= 0; i--)
    {
        for (j = 0; j < 8; j++)
        {
            (*result)[i] = (*result)[i] + ((integer & 1) << j);
            integer = integer >> 1;
        }
    }
    QByteArray final = *result;
    delete result;
    return final;
}

//Encodes a fixed size header for the packet using getPacketId and getBodySize templates.
QByteArray Packet::getHeader() {
    if (this->getBodySize() > 16777215) qFatal("Size of packet too large");
    QByteArray header(baOfInt(1,this->getPacketId()));
    header.append(baOfInt(3,this->getBodySize()));
    return header;
}

//Casts to Message Packet. Returns null if it not possible.
bool Packet::isMessagePacket() {
    return( this->getPacketId() == Packet::MessagePacketID);
}

//Constant identifier for MessagePackets.
const int Packet::MessagePacketID = 1;

